package com.fms.trollalarm.controller;

import java.util.Calendar;
import java.util.Collection;
import java.util.List;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Vibrator;
import android.util.Log;

import com.fms.trollalarm.database.AlarmDBHelper;
import com.fms.trollalarm.object.AlarmModel;
import com.fms.trollalarm.service.OnAlarmReceiver;
import com.fms.trollalarm.utils.Common.IntentExtra;

public class AlarmController {
	private Context context;
	private AlarmDBHelper dbHelper;
	private final Handler handler;
	private Ringtone ringtone;
	private Runnable runnable;
	private Vibrator vibrator;

	public AlarmController(Context context) {
		super();
		this.context = context;
		this.dbHelper = new AlarmDBHelper(context);
		this.handler = new Handler();
	}

	private void setAlarm(AlarmModel alarm) {
		AlarmManager alarmManager = (AlarmManager) context
				.getSystemService(Context.ALARM_SERVICE);
		PendingIntent pendingIntent = getPendingIntent(alarm);
		if (alarm.getId() >= 0) {
			alarmManager.cancel(pendingIntent);
		}
		Calendar calendar = Calendar.getInstance();
		if ((calendar.get(Calendar.HOUR_OF_DAY) > alarm.getTimeHour())
				|| ((calendar.get(Calendar.HOUR_OF_DAY) == alarm.getTimeHour()) && (calendar
						.get(Calendar.MINUTE) > alarm.getTimeMinute()))) {
			calendar.add(Calendar.DATE, 1);
		}
		calendar.set(Calendar.HOUR_OF_DAY, alarm.getTimeHour());
		calendar.set(Calendar.MINUTE, alarm.getTimeMinute());
		calendar.set(Calendar.SECOND, 0);
		if (alarm.isRepeatWeekly()) {
			alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
					calendar.getTimeInMillis(), 86400000L, pendingIntent);

		} else {
			alarmManager.set(AlarmManager.RTC_WAKEUP,
					calendar.getTimeInMillis(), pendingIntent);
		}
	}

	private PendingIntent getPendingIntent(AlarmModel alarm) {
		Intent intent = new Intent(context, OnAlarmReceiver.class);
		intent.putExtra(IntentExtra.ID, alarm.getId());
		return PendingIntent.getBroadcast(context, (int) alarm.getId(), intent,
				PendingIntent.FLAG_UPDATE_CURRENT);
	}

	private void cancelAlarm(AlarmModel alarm) {
		AlarmManager alarmManager = (AlarmManager) context
				.getSystemService(Context.ALARM_SERVICE);
		PendingIntent pendingIntent = getPendingIntent(alarm);
		if (alarm.getId() >= 0) {
			alarmManager.cancel(pendingIntent);
		}
	}

	public long createAlarm(AlarmModel alarm) {
		long id = dbHelper.createAlarm(alarm);
		Log.d("fms", "alarm id " + id);
		if (id != -1) {
			alarm.setId(id);
			setAlarm(alarm);
		}
		return id;
	}

	public void updateAlarm(AlarmModel alarm) {
		long num = dbHelper.updateAlarm(alarm);
		if (num > 0) {
			if (alarm.isEnabled()) {
				setAlarm(alarm);
			} else {
				cancelAlarm(alarm);
			}
		}
	}

	public AlarmModel getAlarm(long id) {
		return dbHelper.getAlarm(id);
	}

	public Collection<? extends AlarmModel> getAlarms() {
		return dbHelper.getAlarms();
	}

	public void deleteAlarm(AlarmModel alarmDetails) {
		int num = dbHelper.deleteAlarm(alarmDetails.getId());
		if (num > 0) {
			cancelAlarm(alarmDetails);
		}
	}

	public void loadAllAlarms() {
		List<AlarmModel> alarms = dbHelper.getAlarms();
		for (AlarmModel alarmModel : alarms) {
			if (alarmModel.isEnabled()) {
				setAlarm(alarmModel);
			}
		}
	}

	public void startAlarm(AlarmModel alarm) {
		playRingtoneAndVibrate(alarm.getAlarmTone(), alarm.isVibrate(), 0);
	}

	private void startVibrate() {
		vibrator = (Vibrator) context
				.getSystemService(Context.VIBRATOR_SERVICE);
		long[] pattern = { 0, 50, 100, 50, 100, 50, 100, 400, 100, 300, 100,
				350, 50, 200, 100, 100, 50, 600 };
		vibrator.vibrate(pattern, 0);
	}

	public void stopAlarm(AlarmModel alarm) {
		stopRingtoneAndVibrate();
		if (!alarm.isRepeatWeekly()) {
			alarm.setEnabled(false);
			updateAlarm(alarm);
		}
	}

	private void stopRingtoneAndVibrate() {
		ringtone.stop();
		if (vibrator != null && vibrator.hasVibrator()) {
			vibrator.cancel();
		}
		handler.removeCallbacks(runnable);
	}

	private void playRingtoneAndVibrate(Uri ringtoneUri,
			final boolean isVibrate, long timeDelay) {
		AudioManager audioManager = (AudioManager) context
				.getSystemService(Context.AUDIO_SERVICE);

		ringtone = RingtoneManager.getRingtone(context, ringtoneUri);
		int maxVolume = audioManager
				.getStreamMaxVolume(AudioManager.STREAM_ALARM);

		audioManager.setStreamVolume(AudioManager.STREAM_ALARM, maxVolume,
				AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
		ringtone.setStreamType(AudioManager.STREAM_ALARM);// RingtoneManager.TYPE_ALARM
		runnable = new Runnable() {

			@Override
			public void run() {
				if (!ringtone.isPlaying()) {
					ringtone.play();
				}
				handler.postDelayed(this, 1000L);
				if (isVibrate) {
					startVibrate();
				}
			}
		};
		handler.postDelayed(runnable, timeDelay);
	}

	public void snooze(AlarmModel alarm, long snoozeTime) {
		stopRingtoneAndVibrate();
		playRingtoneAndVibrate(alarm.getAlarmTone(), alarm.isVibrate(),
				snoozeTime);
	}

}